package others;

import com.google.common.util.concurrent.RateLimiter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.concurrent.locks.ReentrantLock;

import static java.lang.Math.max;
import static java.lang.Math.min;


/**
 * @author ycz
 * @date 2021/5/20
 * @description TODO
 *
 */
public class rateLimiterTest {

    public void method() {
        synchronized (this) {
            System.out.println("Method 1 start");
        }
    }

    public void lockTest() {
        ReentrantLock reentrantLock = new ReentrantLock();
        reentrantLock.lock();
        reentrantLock.tryLock();
        System.out.println("123");
        reentrantLock.unlock();
        reentrantLock.unlock();
    }

    public void intTest() {
        int a = 1;
        a++;
        System.out.println(a);
    }

    public void testHuibianVolatile() {
        storedPermits++;
    }


    // 当前令牌桶的令牌数量
    volatile long storedPermits = 0;
    // 令牌桶的容量
    long maxPermits = 3;
    // 下一令牌产生时间
    long next = System.nanoTime();
    // 发放令牌间隔 纳秒
    long interval = 1000_000_000;

    /**
     * 请求时间在下一令牌产生时间之后，则
     * 1、重新计算令牌桶中的令牌书
     * 2、将下一个令牌发放时间重置为当前时间
     */
    void resync(long now) {
        if (now > next) {
            // 新产生的令牌数量
            long newPermits = (now - next) / interval;
            // 新令牌添加到令牌桶
            storedPermits = min(maxPermits, storedPermits + newPermits);
            next = now;
        }
    }

    /**
     * 预占令牌，返回能够获取令牌的时间
     */
    synchronized long reserve(long now) {
        resync(now);
        // 能够获取令牌的时间
        long at = next;
        // 令牌桶中能提供的令牌
        long fd = min(maxPermits, storedPermits);
        // 令牌扣减
        long nr = 1 - fd;
        // 重新计算下一令牌产生时间
        next = next + nr * interval;
        this.storedPermits -= fd;
        return at;
    }

    /**
     * 申请令牌
     */
    void acquire() {
        // 申请令牌时间
        long now = System.nanoTime();
        // 预占令牌
        long at = reserve(now);
        long waitTime = max(at - now, 0);

        // TODO
        if (waitTime > 0) {

        }
    }


    public static void main(String[] args) throws Exception {

        // 每秒2个请求
        RateLimiter rateLimiter = RateLimiter.create(1000);
        Thread.sleep(20);
        System.out.println(rateLimiter.getRate());
        // acquire是阻塞的且会一直等待到获取令牌为止，它有一个返回值为double型，意思是从阻塞开始到获取到令牌的等待时间，单位为秒
        rateLimiter.acquire(5);
        // tryAcquire是另外一个方法，它可以指定超时时间，返回值为boolean型，即假设线程等待了指定时间后仍然没有获取到令牌，那么就会返回给客户端false，客户端根据自身情况是打回给前台错误还是定时重试
//        boolean tryAcquire = rateLimiter.tryAcquire(5);
        System.out.println(rateLimiter.acquire(5));
        System.out.println(rateLimiter.tryAcquire(5));
        System.out.println(rateLimiter.tryAcquire());
        System.out.println(rateLimiter.tryAcquire());
        System.out.println(rateLimiter.tryAcquire());
        System.out.println(rateLimiter.tryAcquire());
        System.out.println(rateLimiter.tryAcquire());
        System.out.println(rateLimiter.tryAcquire());
        System.out.println(rateLimiter.tryAcquire());
        System.out.println(rateLimiter.tryAcquire());
        System.out.println(rateLimiter.tryAcquire());
        System.out.println(rateLimiter.tryAcquire());
        System.out.println(rateLimiter.tryAcquire());
        System.out.println(rateLimiter.tryAcquire());
        System.out.println(rateLimiter.tryAcquire());

//        Class<?> aClass = Class.forName(String.valueOf(rateLimiter.getClass()));

        AtomicBoolean atomicBoolean = new AtomicBoolean();
        atomicBoolean.set(false);
        AtomicInteger atomicInteger = new AtomicInteger();
        atomicInteger.set(5);

        List<String> strings = new ArrayList<>();
        strings.add("12");
        HashMap<Object, Object> map = new HashMap<>();
        map.put("a", "a");

        ConcurrentHashMap<Object, Object> concurrentHashMap = new ConcurrentHashMap<>();
        concurrentHashMap.put("a", "a");

        System.out.println(123456 & 15);
        System.out.println(123456 & 7);
        System.out.println(123456 & 3);
        System.out.println("========");
        System.out.println(3 & 99999);
        System.out.println(7 & 88888);
        System.out.println(15 & 77777);
        System.out.println(7 & 77777);
        System.out.println(31 & 77777);

        String a = "a";
        String b = "b";
        String b2 = "b";
        String and = a + b;
        String ab = "ab";
        String ab2 = "ab";
        String s = new String("a");
        System.out.println(a == b);
        System.out.println(s == a);
        System.out.println(and == ab);

        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("");

        ArrayList<Integer> list = new ArrayList<Integer>();
        ;
        list.add(1);
        list.addAll(list);
        CopyOnWriteArrayList copyOnWriteArrayList = new CopyOnWriteArrayList<String>();
        copyOnWriteArrayList.add(1);
        copyOnWriteArrayList.add("123");
        copyOnWriteArrayList.add(1);

        Random random = new Random(8);
        System.out.println(random.nextInt());

    }

}
